<!DOCTYPE html>
<html>
<body>
<canvas id="canvas" width="3" height="2"></canvas>
<script src="../../resources/js-test.js"></script>
<script>
jsTestIsAsync = true;
var worker = new Worker('./resources/canvas-ImageBitmap-transferable.js');

description("Tests that ImageBitmap is transferable and that the pixel data survives the trip, as well as createImageBitmap(ImageBitmap) works on worker thread");

var imageWidth = 3;
var imageHeight = 2;
var bitmapWidth;
var bitmapHeight;
var newImage;
var newImageBitmap;
var image = new ImageData(new Uint8ClampedArray(
                    [255, 0, 0, 255,
                    0, 255, 0, 255,
                    255, 255, 255, 127,
                    0, 0, 0, 64,
                    12, 34, 56, 64,
                    12, 34, 56, 127]),
                    imageWidth, imageHeight);
var context = document.getElementById("canvas").getContext("2d");

createImageBitmap(image).then(imageBitmap => {
  bitmapWidth = imageBitmap.width;
  bitmapHeight = imageBitmap.height;
  shouldBe("bitmapWidth", "imageWidth");
  shouldBe("bitmapHeight", "imageHeight");

  worker.postMessage({data: imageBitmap}, [imageBitmap]);

  // ImageBitmap has been transferred to worker, main thread loses ownership
  // of it, so the width and height should be 0 now.
  bitmapWidth = imageBitmap.width;
  bitmapHeight = imageBitmap.height;
  shouldBe("bitmapWidth", "0");
  shouldBe("bitmapHeight", "0");

  newImageBitmap = imageBitmap;
  // Test createImageBitmap from neutered ImageBitmap
  createImageBitmap(imageBitmap).then(function() {
      testFailed("Promise accepted, expected to be rejected");
      finishJSTest();
  }, () => {
      testPassed("createImageBitmap from a neutered ImageBitmap was rejected");
  });

  try {
    worker.postMessage({data:imageBitmap});
    testFailed("Apply structured cloning succeed, expected to fail");
  } catch(e) {
    testPassed("Apply structured cloning to a neutered ImageBitmap should throw an exception: " + e);
  }
});

worker.onmessage = function(e) {
  newImageBitmap = e.data.data;
  bitmapWidth = newImageBitmap.width;
  bitmapHeight = newImageBitmap.height;

  // Getting the ImageBitmap back from the worker thread
  shouldBe("bitmapWidth", "imageWidth");
  shouldBe("bitmapHeight", "imageHeight");

  context.drawImage(newImageBitmap, 0, 0);
  newImage = context.getImageData(0, 0, imageWidth, imageHeight);

  // newImage is not necessary the same as imageData because of
  // multiplying and dividing by alpha during the round trip, but
  // they should be close.
  // The alpha channel should be exactly the same.
  shouldBeCloseTo("newImage.data[0]", "image.data[0]", 5);
  shouldBeCloseTo("newImage.data[1]", "image.data[1]", 5);
  shouldBeCloseTo("newImage.data[2]", "image.data[2]", 5);
  shouldBe("newImage.data[3]", "image.data[3]");

  shouldBeCloseTo("newImage.data[4]", "image.data[4]", 5);
  shouldBeCloseTo("newImage.data[5]", "image.data[5]", 5);
  shouldBeCloseTo("newImage.data[6]", "image.data[6]", 5);
  shouldBe("newImage.data[7]", "image.data[7]");

  shouldBeCloseTo("newImage.data[8]", "image.data[8]", 5);
  shouldBeCloseTo("newImage.data[9]", "image.data[9]", 5);
  shouldBeCloseTo("newImage.data[10]", "image.data[10]", 5);
  shouldBe("newImage.data[11]", "image.data[11]");

  shouldBeCloseTo("newImage.data[12]", "image.data[12]", 5);
  shouldBeCloseTo("newImage.data[13]", "image.data[13]", 5);
  shouldBeCloseTo("newImage.data[14]", "image.data[14]", 5);
  shouldBe("newImage.data[15]", "image.data[15]");

  shouldBeCloseTo("newImage.data[16]", "image.data[16]", 5);
  shouldBeCloseTo("newImage.data[17]", "image.data[17]", 5);
  shouldBeCloseTo("newImage.data[18]", "image.data[18]", 5);
  shouldBe("newImage.data[19]", "image.data[19]");

  shouldBeCloseTo("newImage.data[20]", "image.data[20]", 5);
  shouldBeCloseTo("newImage.data[21]", "image.data[21]", 5);
  shouldBeCloseTo("newImage.data[22]", "image.data[22]", 5);
  shouldBe("newImage.data[23]", "image.data[23]");
  finishJSTest();
}

</script>
</body>
</html>
